//---------------------------------------------------------------------------
// NEOPOP : Emulator as in Dreamland
//
// Copyright (c) 2001-2002 by neopop_uk
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//	This program is free software; you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation; either version 2 of the License, or
//	(at your option) any later version. See also the license.txt file for
//	additional informations.
//---------------------------------------------------------------------------

/*
//---------------------------------------------------------------------------
//=========================================================================

	TLCS900h_interpret_single.c

//=========================================================================
//---------------------------------------------------------------------------

  History of changes:
  ===================

20 JUL 2002 - neopop_uk
=======================================
- Cleaned and tidied up for the source release

22 JUL 2002 - neopop_uk
=======================================
- Removed setting the register file pointer to 3 in the SWI instruction
	This has fixed "Metal Slug 2" and flash saving in many games.

26 JUL 2002 - neopop_uk
=======================================
- Prefixed all instruction functions with "sng" to avoid a repeat of the
	the 'EX' fiasco.

30 JUL 2002 - neopop_uk
=======================================
- Um... SWI doesn't cause a problem if IFF is set to 3... why did 
"Metal Slug 2" start working???

//---------------------------------------------------------------------------
*/

#include "../neopop.h"
#include "TLCS900h_interpret.h"
#include "TLCS900h_registers.h"
#include "../mem.h"
#include "../interrupt.h"

namespace TLCS900H
{

//=========================================================================

//===== NOP
void sngNOP()
{
	cycles = 2;
}

//===== NORMAL
void sngNORMAL()
{
	//Not supported
	cycles = 4;
}

//===== PUSH SR
void sngPUSHSR()
{
	push16(sr);
	cycles = 4;
}

//===== POP SR
void sngPOPSR()
{
	sr = pop16();	changedSP();
	cycles = 6;
}

//===== MAX
void sngMAX()
{
	//Not supported
	cycles = 4;
}

//===== HALT
void sngHALT()
{
	MDFN_printf("CPU halt requested and ignored.\nPlease send me a saved state.");
	cycles = 8;
}

//===== EI #3
void sngEI()
{
	setStatusIFF(FETCH8);
	int_check_pending();
	cycles = 5;
}

//===== RETI
void sngRETI()
{
	uint16 temp = pop16();
	pc = pop32();
	sr = temp; changedSP();
	cycles = 12;
}

//===== LD (n), n
void sngLD8_8()
{
	uint8 dst = FETCH8;
	uint8 src = FETCH8;
	storeB(dst, src);
	cycles = 5;
}

//===== PUSH n
void sngPUSH8()
{
	uint8 data = FETCH8;
	push8(data);
	cycles = 4;
}

//===== LD (n), nn
void sngLD8_16()
{
	uint8 dst = FETCH8;
	uint16 src = fetch16();
	storeW(dst, src);
	cycles = 6;
}

//===== PUSH nn
void sngPUSH16()
{
	push16(fetch16());
	cycles = 5;
}

//===== INCF
void sngINCF()
{
	setStatusRFP(((sr & 0x300) >> 8) + 1);
	cycles = 2;
}

//===== DECF
void sngDECF()
{
	setStatusRFP(((sr & 0x300) >> 8) - 1);
	cycles = 2;
}

//===== RET condition
void sngRET()
{
	pc = pop32();
	cycles = 9;
}

//===== RETD dd
void sngRETD()
{
	int16 d = (int16)fetch16();
	pc = pop32();
	REGXSP += d;
	cycles = 9;
}

//===== RCF
void sngRCF()
{
	SETFLAG_N0;
	SETFLAG_V0;
	SETFLAG_C0;
	cycles = 2;
}

//===== SCF
void sngSCF()
{
	SETFLAG_H0;
	SETFLAG_N0;
	SETFLAG_C1;
	cycles = 2;
}

//===== CCF
void sngCCF()
{
	SETFLAG_N0;
	SETFLAG_C(!FLAG_C);
	cycles = 2;
}

//===== ZCF
void sngZCF()
{
	SETFLAG_N0;
	SETFLAG_C(!FLAG_Z);
	cycles = 2;
}

//===== PUSH A
void sngPUSHA()
{
	push8(REGA);
	cycles = 3;
}

//===== POP A
void sngPOPA()
{
	REGA = pop8();
	cycles = 4;
}

//===== EX F,F'
void sngEX()
{
	uint8 f = sr & 0xFF;
	sr = (sr & 0xFF00) | f_dash;
	f_dash = f;
	cycles = 2;
}

//===== LDF #3
void sngLDF()
{
	setStatusRFP(FETCH8);
	cycles = 2;
}

//===== PUSH F
void sngPUSHF()
{
	push8(sr & 0xFF);
	cycles = 3;
}

//===== POP F
void sngPOPF()
{
	sr = (sr & 0xFF00) | pop8();
	cycles = 4;
}

//===== JP nn
void sngJP16()
{
	pc = fetch16();
	cycles = 7;
}

//===== JP nnn
void sngJP24()
{
	pc = fetch24();
	cycles = 7;
}

//===== CALL #16
void sngCALL16()
{
	uint32 target = fetch16();
	push32(pc);
	pc = target;
	cycles = 12;
}

//===== CALL #24
void sngCALL24()
{
	uint32 target = fetch24();
	push32(pc);
	pc = target;
	cycles = 12;
}

//===== CALR $+3+d16
void sngCALR()
{
	int16 displacement = (int16)fetch16();
	uint32 target = pc + displacement;
	push32(pc);
	pc = target;
	cycles = 12;
}

//===== LD R, n
void sngLDB()
{
	regB(first & 7) = FETCH8;
	cycles = 2;
}

//===== PUSH RR
void sngPUSHW()
{
	push16(regW(first & 7));
	cycles = 3;
}

//===== LD RR, nn
void sngLDW()
{
	regW(first & 7) = fetch16();
	cycles = 3;
}

//===== PUSH XRR
void sngPUSHL()
{
	push32(regL(first & 7));
	cycles = 5;
}

//===== LD XRR, nnnn
void sngLDL()
{
	regL(first & 7) = fetch32();
	cycles = 5;
}

//===== POP RR
void sngPOPW()
{
	regW(first & 7) = pop16();
	cycles = 4;
}

//===== POP XRR
void sngPOPL()
{
	regL(first & 7) = pop32();
	cycles = 6;
}

//===== JR cc,PC + d
void sngJR()
{
	if (conditionCode(first & 0xF))
	{
		int8 displacement = (int8)FETCH8;

		cycles = 8;
		pc += displacement;
	}
	else
	{
		cycles = 4;
		FETCH8;
	}
}

//===== JR cc,PC + dd
void sngJRL()
{
	if (conditionCode(first & 0xF))
	{
		int16 displacement = (int16)fetch16();
		cycles = 8;
		pc += displacement;
	}
	else
	{
		cycles = 4;
		fetch16();
	}
}

//===== LDX dst,src
void sngLDX()
{
	uint8 dst, src;

	FETCH8;			//00
	dst = FETCH8;	//#8
	FETCH8;			//00
	src = FETCH8;	//#
	FETCH8;			//00

	storeB(dst, src);
	cycles = 9;
}

//===== SWI num
void sngSWI()
{
	cycles = 16;

	//printf("SWI: %02x\n", first & 0x7);
	switch(first & 7)
	{
		//System Call
	case 1: push32(pc);
			pc = loadL(0xFFFE00 + ((rCodeB(0x31) & 0x1F) << 2));
			break;

	case 3: interrupt(0);	//SWI 3
			break;

	case 4:	interrupt(1);	//SWI 4
			break;

	case 5: interrupt(2);	//SWI 5
			break;

	case 6: interrupt(3);	//SWI 6
			break;

	default:	instruction_error("SWI %d is not valid.", first & 7);
		break;
	}
}
};
//=============================================================================
